<?php
class Model_Mapper_Items {
	
	protected $_dbTable;
	private static $instance;
	
	public static function newInstance() {
		if (! self::$instance instanceof self) {
			self::$instance = new self ();
		}
		return self::$instance;
	}
	
	public function setDbTable($dbTable) {
		if (is_string ( $dbTable )) {
			$dbTable = new $dbTable ();
		}
		if (! $dbTable instanceof Zend_Db_Table_Abstract) {
			throw new Exception ( 'Invalid table data gateway provided' );
		}
		$this->_dbTable = $dbTable;
		return $this;
	}
	
	public function getDbTable() {
		if (null === $this->_dbTable) {
			$this->setDbTable ( 'Model_Table_Items' );
		}
		return $this->_dbTable;
	}
	
	public function save(Model_Items $items) {
		$data = array ('name' => $items->getName (), 'description' => $items->getDescription (), 'user_id' => $items->getUser_id (), 'category_id' => $items->getCategory_id (), 'publish_date' => $items->getPublish_date (), 'modified_date' => $items->getModified_date (), 'expires' => $items->getExpires (), 'price' => $items->getPrice (), 'currency_code' => $items->getCurrency_code (), 'contact_name' => $items->getContact_name (), 'contact_email' => $items->getContact_email (), 'premium' => $items->getPremium (), 'enabled' => $items->getEnabled (), 'active' => $items->getActive (), 'spam' => $items->getSpam (), 'secret' => $items->getSecret (), 'show_email' => $items->getShow_email (), 'slug' => $items->getSlug (), 'urgent' => $items->getUrgent (), 'address_line_1' => $items->getAddress_line_1 (), 'address_line_2' => $items->getAddress_line_2 (), 'local_area' => $items->getLocal_area (), 'location_id' => $items->getLocation_id (), 'postcode' => $items->getPostcode (), 'use_in_map' => $items->getUse_in_map (), 'youtube_url' => $items->getYoutube_url (), 'tags' => $items->getTags (), 'type' => $items->getType (), 'views' => $items->getViews () );
		
		$key = $this->getDbTable ()->getPrimaryKey ();
		$method = 'get' . ucfirst ( $key );
		$val = $items->$method ();
		if ($val == null) {
			unset ( $data [$key] );
			$items->setItem_id ( $this->getDbTable ()->insert ( $data ) );
		} else {
			$this->getDbTable ()->update ( $data, array ($key . ' = ?' => $val ) );
		}
	}
	
	public function getURI($item) {
		if ($item == '') {
			throw new Exception ( 'Empty Item Provided' );
		}
		if (! $item instanceof Model_Items) {
			$item = Model_Mapper_Items::newInstance ()->getByID ( $item );
		}
		if ($item->getCategory_id ()) {
			$uri = Model_Mapper_Categories::newInstance ()->getURI ( $item->getCategory_id (), false );
			$uri = $uri . '/' . $item->getSlug () . '/';
			return sanitizeURI ( $uri );
		}
	}
	
	public function getBySlug($slug) {
		if ($slug == '') {
			throw new Exception ( 'Empty Slug Provided.' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		$select->where ( 'slug=?', $slug );
		$result = $this->extend ( $table->fetchAll ( $select ) );
		if ($result) {
			return $result [0];
		} else {
			return array ();
		}
	}
	
	public function find($query, $args = array(), $start = 0, $count = 50) {
		if ($query == '') {
			throw new Exception ( 'Invalid Query Provided' );
		}
		
		$table = $this->getDbTable ();
		$select = $table->select ();
		$search_category_table = '';
		if (isset ( $args ['where'] ['category_id'] )) {
			$category = Model_Mapper_Categories::newInstance ()->getByID ( $args ['where'] ['category_id'] );
			if (file_exists ( plugin_path () . $category->getSlug () . DS . 'search.php' )) {
				include plugin_path () . $category->getSlug () . DS . 'search.php';
			}
		}
		$select->from ( $table );
		if ($search_category_table != '') {
			$select->setIntegrityCheck ( false );
			$select->joinInner ( $search_category_table->getTableName (), $search_category_table->getTableName () . '.' . $search_category_table->getPrimaryKey () . '=' . $table->getTableName () . '.' . $table->getPrimaryKey () );
		}
		
		if ($args ['where'] != '') {
			foreach ( $args ['where'] as $key => $value ) {
				if (strpos ( $key, '?' )) {
					$select->where ( $key, $value );
				} else {
					$select->where ( $key . '=?', $value );
				}
			}
		}
		
		if ($args ['expr']) {
			foreach ( $args ['expr'] as $q ) {
				$select->columns ( new Zend_Db_Expr ( $q ) );
			}
		}
		
		$select->order ( 'urgent DESC' );
		
		if ($args ['order'] != '') {
			foreach ( $args ['order'] as $order ) {
				$select->order ( $order );
			}
		}
		$select->order ( 'score DESC' );
		
		/* ADD SCORE */
		$select->having ( 'score >?', 0 );
		if ($args ['having'] != '') {
			foreach ( $args ['having'] as $having ) {
				$select->having ( $having );
			}
		}
		//echo $select;
		if ($args ['limit'] != '') {
			$select->limitPage ( $args ['limit'] ['page'], $args ['limit'] ['count'] );
		}
		//echo $select.PHP_EOL;
		return $this->extend ( $table->fetchAll ( $select ) );
	}
	
	public function getByTag($tag, $page = 0, $rowCount = 'all') {
		if ($tag == '') {
			throw new Exception ( 'Invalid Tag Provided.' );
		}
		$tag = str_replace ( '%20', ' ', $tag );
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		$select->columns ( new Zend_Db_Expr ( 'MATCH (tags) AGAINST (\'' . $tag . '\') as score' ) );
		$select->having ( 'score >?', 0 );
		$select->order ( 'urgent DESC' );
		$select->order ( 'publish_date DESC' );
		$select->order ( 'score DESC' );
		if (! $rowCount == 'all') {
			$select->limitPage ( $page, $rowCount );
		}
		//echo $select;
		return $this->extend ( $table->fetchAll ( $select ) );
	}
	
	public function getByLocation() {
	
	}
	
	public function getBySecret($secret = '') {
		if ($secret == '') {
			throw new Exception ( 'Invalid Secret provided for the item.' );
		}
		$args = array ('secret' => $secret );
		$result = $this->getByCondition ( $args );
		if ($result) {
			return $result [0];
		} else {
			return array ();
		}
	}
	
	public function getByCategory($category, $array = false, $recursive = false, $args = array()) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		if (! $category instanceof Model_Categories) {
			$category = Model_Mapper_Categories::newInstance ()->getByID ( $category );
		}
		$cats = array ();
		if ($recursive) {
			$cats = Model_Mapper_Categories::newInstance ()->getSubCategories ( $category, true, true );
		} else {
			$cats [] = array ('category_id' => $category->getCategory_id () );
		}
		$ids = array ();
		$ids [] = $category->getCategory_id ();
		foreach ( $cats as $cat ) {
			$ids [] = $cat ['category_id'];
		}
		
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		$select->where ( 'category_id IN (?)', $ids );
		if ($args) {
			foreach ( $args as $k => $v ) {
				if (is_array ( $v )) {
					$str = $k . ' IN (?)';
					$select->where ( $str, $v );
				} else {
					$select->where ( $k . '=?', $v );
				}
			
			}
		}
		
		$select->order ( array ('modified_date DESC' ) );
		
		$result = $table->fetchAll ( $select );
		
		$result = $this->extend ( $result );
		
		if ($result) {
			if ($array) {
				foreach ( $result as $key => $item ) {
					$result [$key] = $item->toArray ();
				}
			}
			
			return $result;
		
		} else {
			return array ();
		}
		
	/*} else {
	$args = array ('category_id' => $category->getCategory_id () );
	
	$result = $this->getByCondition ( $args );
	if ($result) {
		if ($array) {
			foreach ( $result as $key => $item ) {
				$result [$key] = $item->toArray ();
			}
		}
		return $result;
	} else {
		return array ();
	}
}*/
	
	}
	
	public function getByCondition($args, $array = false) {
		if (! is_array ( $args )) {
			throw new Exception ( 'Invalid Argument Array Provided' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		
		foreach ( $args as $key => $value ) {
			if (is_array ( $value )) {
				$select->where ( $key . ' IN (?)', $value );
			} else {
				$select->where ( $key . '=?', $value );
			}
		
		}
		
		$result = $table->fetchAll ( $select );
		$result = $this->extend ( $result );
		if ($result) {
			if ($array) {
				foreach ( $result as $key => $item ) {
					$result [$key] = $item->toArray ();
				}
			}
			
			return $result;
		
		} else {
			return array ();
		}
	}
	
	private function extend($args) {
		$items = array ();
		foreach ( $args as $arg ) {
			$arg = $arg->toArray ();
			$item = new Model_Items ( $arg );
			$items [] = $item;
		}
		return $items;
	}
	
	public function lastInsertID() {
		return $this->getDbTable ()->getAdapter ()->lastInsertId ();
	}
	
	public function beginTransaction() {
		$this->getDbTable ()->getAdapter ()->beginTransaction ();
	}
	
	public function commit() {
		$this->getDbTable ()->getAdapter ()->commit ();
	}
	
	public function rollBack() {
		$this->getDbTable ()->getAdapter ()->rollBack ();
	}
	
	public function getAll($enabled = false) {
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $this->getDbTable () );
		if ($enabled) {
			$select->where ( 'enabled=?', 1 );
		}
		
		return $this->extend ( $table->fetchAll ( $select ) );
	}
	
	public function getEditURL($item, $admin = true) {
		
		if ($item == '') {
			throw new Exception ( 'Empty Item Provided' );
		}
		if (! $item instanceof Model_Items) {
			$item = Model_Mapper_Items::newInstance ()->getByID ( $item );
		}
		
		if ($admin) {
			$uri = cp_url () . '?page=edit&action=edit&item_id=' . $item->getItem_id ();
			return sanitizeURI ( $uri );
		} else {
			// place code here to return frontend item edit url
		}
	}
	
	public function getDeleteURL($item, $admin = true) {
		if ($item == '') {
			throw new Exception ( 'Empty Item Provided' );
		}
		if (! $item instanceof Model_Items) {
			$item = Model_Mapper_Items::newInstance ()->getByID ( $item );
		}
		
		if ($admin) {
			$uri = cp_url () . '?page=items&action=delete&item_id=' . $item->getItem_id ();
			return sanitizeURI ( $uri );
		} else {
			// place code here to return frontend item edit url
		}
	}
	
	public function getByID($id) {
		if ($id == '') {
			throw new Exception ( 'Invalid ID Provided.' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->where ( $this->getDbTable ()->getPrimaryKey () . '=?', $id );
		$select->from ( $this->getDbTable () );
		$result = $this->extend ( $table->fetchAll ( $select ) );
		return $result [0];
	}

}